<template>
  <div class="init-container">
    <div class="mask-container" v-if="isMask"></div>
    <div class="none-container" v-if="nonePermission">
      {{ $srv.getI18nByPath('others.noPermissions') }}···
    </div>
    <o-flowchart
      ref="flowchart"
      :itemList="items"
      :compBoxInfo="GT_compBoxInfo"
      @on-canvas-click="onCanvasClick"
      @on-node-select="onNodeSelect"
      @on-edge-select="onEdgeSelect"
      @on-graph-editor-state="onGraphEditorState"
      @on-graph-toolbar-click="onGraphToolbarClick"
      @compBoxInfo="flowchartInit"
      @on-node-right-click="onNodeRightClick"
      @on-after-render="onAfterRender"
    >
      <template #comp>
        <o-card-box
          ref="cardBox"
          :isExpand="isShowNodeForm"
          position="right"
          :width="nodeAttrWidth"
          :disabled="nodeAttrDisabled"
          @on-change="onCardBoxValChange"
        >
          <div class="node-attr">
            <div class="title">{{ $srv.getI18nByValue('属性设置') }}</div>
            <Collapse v-model="nodeAttrModal">
              <Panel name="1" class="panel"
                >{{ $srv.getI18nByValue('图属性') }}
                <div class="label" slot="content">
                  <div class="label-id">ID:</div>
                  <div class="input">
                    <Input disabled v-model="nodeAttrData.nodeID" />
                  </div>
                </div>
                <div class="label" slot="content">
                  <div class="label-name">
                    {{ $srv.getI18nByValue('名称') }}:
                  </div>
                  <div class="input">
                    <Input
                      :disabled="nodeAttrLabelDisabled"
                      v-model="nodeAttrData.nodeLabel"
                      :placeholder="$srv.getI18nByValue('请输入节点名')"
                      @on-change="onAttrNodeLabelChange"
                    />
                  </div>
                </div>
              </Panel>
              <Panel name="2" class="panel"
                >{{ $srv.getI18nByValue('节点数据') }}
                <div slot="content">
                  <o-base-form
                    ref="attrForm"
                    :parentCommand="GT_command"
                    :mode="1"
                    @on-change="onAttrChange"
                  ></o-base-form>
                </div>
              </Panel>
              <Panel name="3" class="panel"
                >{{ $srv.getI18nByValue('主表数据') }}
                <div slot="content">
                  <o-base-form
                    ref="attrMainForm"
                    :parentCommand="GT_command"
                    :mode="1"
                    @on-change="onAttrMainChange"
                  ></o-base-form>
                </div>
              </Panel>
            </Collapse>
          </div>
        </o-card-box>
      </template>
      <template #openData>
        <openGraphData
          :compBoxInfo="GT_compBoxInfo"
          :config="_config"
          @on-cell-dblclick="onCellDblclick"
        />
      </template>
    </o-flowchart>
  </div>
</template>

<script lang="ts">
import { N_oFlowchart, N_oSetupPanel } from '@/types';
import {
  I_cmd,
  T_cmd,
  T_srv,
  Tsrv,
  customGraphReg,
  defItems,
  ifs,
  openGraphData,
  vue
} from './config';

@T_srv.comp({
  components: {
    openGraphData
  }
})
export default class oGraph extends vue {
  /* 父组件compBoxInfo */
  @T_srv.prop({
    required: false,
    type: Object,
    default: null
  })
  compBoxInfo: ifs.I_compBoxInfo;

  @T_srv.prop({
    required: false,
    type: Object,
    default: null
  })
  config: any;

  // config副本
  private _config: any = null;

  public viewContainer: string = Tsrv.utils.custUUID(8);

  private name: string = 'oGraph';

  /* 组件名 */
  private G_compName: string = this.name;

  /* 组件箱信息对象 */
  private GT_compBoxInfo: ifs.I_compBoxInfo;

  /* 组件箱对象 */
  private GT_compBox: ifs.I_compBox;

  /* 组件箱识别ID */
  private G_compID: string;

  public items: Array<any> = defItems();

  /* 指挥部 */
  private GT_command: I_cmd = new T_cmd();

  private defListenersEventNames: Array<string> = [];

  public isShowNodeForm: boolean = false;

  public nodeAttrWidth: number = 250;

  public isMask: boolean = false;

  private nonePermission: boolean = false;

  public nodeAttrData: any = {
    nodeID: '',
    nodeLabel: ''
  };

  public nodeAttrLabelDisabled: boolean = true;

  private currNode: any = null;

  public nodeAttrDisabled: boolean = true;

  public nodeAttrModal = ['1', '2', '3'];

  public mainFunName: string = '';

  public funName: string = '';

  private actionCfg: any = null;

  @T_srv.ref('flowchart') refFlowchart: N_oFlowchart.oFlowchart;

  @T_srv.ref('attrForm') refAttrForm: any;

  @T_srv.ref('attrMainForm') refAttrMainForm: any;

  @T_srv.ref('cardBox') refCardBox: any;

  created() {
    this._config = Tsrv.utils.clone(this.config, true);
    customGraphReg.customEdge.init();
    customGraphReg.customNode.init();
    customGraphReg.customLayout.init();
    // 如果父组件没有传参，那就产生一个
    this.GT_compBoxInfo = Tsrv.getCompInfo(this.compBoxInfo);
    this.G_compID = this.GT_compBoxInfo.compID;
    this.GT_compBox = this.GT_compBoxInfo.TcompBox;
    this.GT_command.init(this, this.GT_compBoxInfo);
    this.initConfig();

    // 功能“浏览”权限
    const defaultPermission = Tsrv.utils.find(
      this._config.permission,
      item => item.area === 'default'
    );
    this.nonePermission = !defaultPermission?.data?.browse;
  }

  private initConfig() {
    this.GT_command.newTcompCoordination(this._config);
    this.mainFunName = this._config?.mainFun || ''; // 主功能
    this.funName = this._config?.name || ''; // 功能
    if (!Tsrv.noValue(this._config.action)) {
      this.actionCfg = Tsrv.utils.clone(this._config.action);
      // delete this._config.action;
    }
    // Tsrv.getI18nByValue;
    if (
      Tsrv.utils.noValue(this._config?.name) ||
      Tsrv.utils.noValue(this._config?.dbType)
    ) {
      throw new Error('值参空');
    }
    this.GT_command.tableName = this._config.name;
    this.GT_command.dbType = this._config.dbType;
    // this.loadEventName = this._config.name;

    this.getDefListener();
    // setTimeout(() => {
    //   Tsrv.getFunConf(this._config.name).then(ele => {
    //     if (ele.isErr()) {
    //       this.$msg(ele.errmsg);
    //     } else {
    //       const key: string = this._config.name.toString();
    //       this.GT_command.nodeColumns = ele.getReturnData(key).nodeColumns;
    //       const cols = ele.getReturnData(key).tableColumns ?? [];
    //       this.GT_command.tableColumns = cols.filter(
    //         el =>
    //           !el?.nodeData &&
    //           el.field !== 'id' &&
    //           el.field !== Tsrv.globalVar.fieldName.masterBillId &&
    //           el.field !== Tsrv.globalVar.fieldName.nodeID
    //       );
    //     }
    //   });
    // }, 500);
  }

  private getDefListener() {
    const custDefListener = this._config?.messageConfig?.custDefListener;
    if (!Tsrv.utils.noValue(custDefListener)) {
      let isNull = true;
      Object.keys(custDefListener).forEach(key => {
        if (!Tsrv.utils.noValue(custDefListener[key])) {
          isNull = false;
          // this.defListenersEventNames.push(...custDefListener[key]);
          if (Array.isArray(custDefListener[key])) {
            this.defListenersEventNames.push(...custDefListener[key]);
          } else if (typeof custDefListener[key] === 'string') {
            this.defListenersEventNames.push(custDefListener[key]);
          } else {
            throw new Error(`无法识别的事件监听[${custDefListener[key]}]`);
          }
        }
      });
      if (isNull) {
        this.defListenersEventNames.push(this._config.name);
      }
    } else {
      this.defListenersEventNames.push(this._config.name);
    }
  }

  mounted() {
    /* 向父组件发送实例 */
    this.GT_compBox.addCompMergeName(this.G_compID, this.G_compName, this);
    this.$emit('compBoxInfo', this.GT_compBoxInfo);
    /* 最终应用组件向外抛出引用实例,以供应用间调用 */
    Tsrv.compBox.addCompMergeName(
      Tsrv.compBox.getDefGUID(), // 全局compBox
      this.funName,
      this
    );
    const that = this;

    this.defListenersEventNames.forEach(eN => {
      this.$bus.$on(eN, (msg: any) => {
        if (msg.type === 'coordination') {
          this.GT_command.receEventCoordination(msg);
        } else if (msg.listenType === 'default' && msg.type === 'search') {
          this.GT_command.setFieldsSearchFilter();
          const pID = msg.option.autoCompleteInfo.key;
          const associationField = msg.content.ukey;
          if (Tsrv.utils.noValue(pID) || Tsrv.utils.noValue(associationField)) {
            this.$msg(Tsrv.getI18nByValue('未获取主单ID'));
            throw new Error('未获取主单ID');
          }
          that.GT_command.currParentID = pID;
          that.GT_command.associationField = associationField;
          this.isShowNodeForm = false;
          that.GT_command.loadData(msg);
        }
      });
      this.$mbus.$on(eN, (msg: any) => {
        if (msg.type === 'coordination') {
          this.GT_command.receEventCoordination(msg);
        } else if (msg.listenType === 'magicbox' && msg.type === 'search') {
          const pID = msg.option.autoCompleteInfo.key;
          const associationField = msg.content.ukey;
          if (Tsrv.utils.noValue(pID) || Tsrv.utils.noValue(associationField)) {
            this.$msg(Tsrv.getI18nByValue('未获取主单ID'));
            throw new Error('未获取主单ID');
          }
          that.GT_command.currParentID = pID;
          that.GT_command.associationField = associationField;
          this.isShowNodeForm = false;
          that.GT_command.loadData(msg);
        }
      });
    });
    this.$nextTick(() => {
      Tsrv.getFunConf(this._config.name).then(ele => {
        if (ele.isErr()) {
          this.$msg(ele.errmsg);
        } else {
          const key: string = this._config.name.toString();
          this.GT_command.nodeColumns = ele.getReturnData(key).nodeColumns;
          const cols = ele.getReturnData(key).tableColumns ?? [];
          this.GT_command.tableColumns = cols.filter(
            el =>
              !el?.nodeData &&
              el.field !== 'id' &&
              el.field !== Tsrv.globalVar.fieldName.masterBillId &&
              el.field !== Tsrv.globalVar.fieldName.nodeID
          );
        }
      });
    });
  }

  destroyed() {
    /* 注册组件销毁 */
    this.GT_compBox.removeCompMergeName(this.G_compID, this.G_compName);

    /* 如果父组件传入的compBoxInfo则删除本文件产生的引用,反之是本组件产生的ID统一删除 */
    if (Tsrv.utils.isEmpty(this.compBoxInfo)) {
      this.GT_compBox.removeCompsWithCompID(this.G_compID);
    } else {
      this.GT_compBox.removeCompsMergeName(this.G_compID, [
        `'${this.G_compName}'`
      ]);
    }
    /* 最终应用组件销毁 */
    Tsrv.compBox.removeCompMergeName(Tsrv.compBox.getDefGUID(), this.funName);

    this.defListenersEventNames.forEach(eN => {
      this.$bus.$off(eN);
    });
  }

  onCanvasClick(e: any) {}

  onNodeSelect(e: any) {
    this.isShowNodeForm = false;
    if (e.item.getType() !== 'node' || e.item.getModel().type === 'gIfNode') {
      return;
    }
    const nodeID = e.item.getID();
    if (Tsrv.utils.noValue(nodeID)) {
      return;
    }

    this.searchChildComp(nodeID, e.item.getModel());
  }

  private searchChildComp(nodeID: string, nodeModel: any) {
    if (this.GT_command.graphEditorState !== 'none') {
      return;
    }
    // 发送search事件
    if (!Tsrv.utils.noValue(this._config?.messageConfig)) {
      const emitActions = this._config.messageConfig?.emitActions;
      if (!Tsrv.utils.noValue(emitActions)) {
        emitActions.search.forEach(ele => {
          if (ele.toID) {
            const uk = ele.msg.content.ukey;
            const val = this.GT_command.oldGraphRec.id ?? nodeModel.id;
            const ev = {
              type: 'search',
              content: {
                ikey: ele.msg.content.ikey,
                ukey: uk,
                val: [val],
                where: { $and: [{ [uk]: val }, { node_id: nodeID }] }
              },
              listenType: 'default',
              option: {
                autoCompleteInfo: {
                  defaultVal: [{ field: 'node_id', value: nodeID }],

                  key: this.GT_command.oldGraphRec.id ?? nodeModel.id, // 这里填上要传的key
                  table: this._config.name,
                  data: this.GT_command.oldMainRec,
                  nodeData: nodeModel
                }
              }
            };
            this.sendBusEvent(ele.toID, ev);
          }
        });
      }
    }
  }

  sendBusEvent(name: string, msg: any) {
    if (this.GT_command.graphEditorState !== 'none') {
      return;
    }
    Tsrv.reliablySendingBusEvent(name, this.$bus, 10, 100, msg);
  }

  onEdgeSelect(e: any) {}

  onGraphEditorState(p: string) {
    if (this.GT_command.oldMainRec && p === 'new') {
      this.GT_command.graphEditorState = 'modify'; // 当有数据时不能听画布发出的状态
    } else {
      this.GT_command.graphEditorState = p;
    }
  }

  beforeSave(e): Promise<boolean> {
    return new Promise(resolv => {
      this.GT_command.doSave(e).then(b => {
        if (b) {
          this.GT_command.graphEditorState = 'none';
          this.isShowNodeForm = false;

          this.GT_command.loadData(this.GT_command.searchEventMsg);
          resolv(true);
        }
        resolv(false);
      });
    });
  }

  // 刷新子组件
  cleanSubCompData(p: N_oSetupPanel.N_comps.T_eventCoordinationToolbar) {
    const emitActions = this._config.messageConfig?.emitActions;
    if (!Tsrv.utils.noValue(emitActions)) {
      emitActions.search.forEach(ele => {
        if (ele.toID) {
          const uk = ele.msg.content.ukey;
          const val = -1;
          const ev = {
            type: 'search',
            content: {
              ikey: ele.msg.content.ikey,
              ukey: uk,
              val: [val],
              where: { $and: [{ [uk]: val }, { node_id: '-1' }] }
            },
            listenType: 'default',
            option: {
              autoCompleteInfo: {
                defaultVal: [{ field: 'node_id', value: '-1' }],

                key: -1, // 这里填上要传的key
                table: this._config.name,
                data: { data: { id: '-1' } },
                nodeData: null
              }
            }
          };
          this.sendBusEvent(ele.toID, ev);
        }
      });
    }
  }

  beforeNew(e): Promise<boolean> {
    return new Promise(resolv => {
      if (Tsrv.utils.noValue(this.GT_command.oldGraphRec?.f_data)) {
        resolv(true);
      }
      const nodeData = JSON.parse(this.GT_command.oldGraphRec?.f_data)?.nodes;

      if (!Tsrv.utils.noValue(nodeData)) {
        this.$srv.dialog
          .confirm(
            Tsrv.getI18nByValue('新建数据会覆盖源数据,请确认!'),
            Tsrv.getI18nByValue('警告')
          )
          .then(s => {
            if (s === 'confirm') {
              resolv(true);
            } else {
              resolv(false);
            }
          })
          .catch(err => {
            this.$msg(err);
            resolv(false);
          });
      } else {
        resolv(true);
      }
    });
  }

  onGraphToolbarClick(e: N_oFlowchart.I_toolbarClick) {
    switch (e.key) {
      case 'open':
        this.GT_command.openData();
        break;
      case 'save':
        this.GT_command.sendEventCoordination('save');
        break;
      case 'new':
        this.GT_command.sendEventCoordination('insert');
        break;
      case 'edit':
        this.GT_command.sendEventCoordination('edit');
        break;
      case 'cancelEdit':
        // this.isShowNodeForm = false;
        this.refCardBox.closeCardBox();
        this.GT_command.sendEventCoordination('refresh');
        break;
      default:
      // throw new Error('不能识别的类型');
    }
  }

  flowchartInit(e) {
    // 函数注册
    this.refFlowchart.regFns([
      // { name: 'beforeHandleNodeAndEdge', fn: beforeHandleNodeAndEdge }
      { name: 'before_new', fn: this.beforeNew },
      // { name: 'after_save', fn: this.afterSave },
      { name: 'before_save', fn: this.beforeSave }
      // { name: 'after_edit', fn: this.afterEdit },
      // { name: 'after_audit', fn: this.afterAudit },
      // { name: 'after_unAudit', fn: this.afterUnAudit }
    ]);
    this.GT_command.setPermission(this._config);
  }

  onCellDblclick(e: any) {
    this.GT_command.tableColumnData.clear();
    const rec = Tsrv.utils.clone(e.row, true);
    delete rec['_XID'];
    delete rec['_file_info_id_'];
    delete rec['_sort_'];
    this.GT_command.oldMainRec = rec;
    this.GT_command.loadGraph(e);
  }

  onNodeRightClick(e) {
    if (this.nodeAttrDisabled) {
      return;
    }

    this.currNode = e.e;
    this.isShowNodeForm = true;

    const m = e.e.item.getModel();
    const nodeFormData = { node_id: e.e.item._cfg.id };
    if (m?.data) {
      m.data.forEach(d => {
        nodeFormData[d.field] = d.value;
      });
    }
    this.nodeAttrData['nodeLabel'] = e.e.item.getModel().label;
    this.nodeAttrData['nodeID'] = e.e.item._cfg.id;
    this.attrForm(nodeFormData);
    this.attrMainForm();
  }

  private attrForm(nodeFormData: any) {
    const columns: Array<any> = this.refAttrForm.transformColumns(
      this.GT_command.nodeColumns
    );
    if (
      columns.findIndex(el => el.field === Tsrv.globalVar.fieldName.nodeID) ===
      -1
    ) {
      this.$msg(Tsrv.getI18nByValue('缺少必须字段[node_id]'));
      throw new Error(Tsrv.getI18nByValue('缺少必须字段[node_id]'));
    }

    this.refAttrForm.setFormData(nodeFormData);
    this.refAttrForm.setColumns(columns);

    if (this.GT_command.graphEditorState === 'none') {
      this.refAttrForm.setModify(false);
    } else {
      this.refAttrForm.setModify(true);
    }
  }

  private attrMainForm() {
    const columns: Array<any> = this.refAttrForm.transformColumns(
      this.GT_command.tableColumns
    );
    const tableColumnData = {};
    columns.forEach(col => {
      let fieldName = col.title;
      const eFs = fieldName.split('|');
      if (eFs.length === 4 && eFs[0] === 'm2o') {
        fieldName = eFs[1];
      } else if (eFs.length === 3 && eFs[0] === 'slc') {
        fieldName = eFs[1];
      }
      let v = this.GT_command.tableColumnData.get(fieldName);
      if (!v) {
        v = null;
        if (
          this.GT_command.oldMainRec &&
          this.GT_command.oldMainRec[fieldName]
        ) {
          v = this.GT_command.oldMainRec[fieldName];
        }
      }
      this.GT_command.tableColumnData.set(fieldName, v);
      tableColumnData[fieldName] = v;
      // m2o slc
      if (fieldName !== col.field) {
        let vv = this.GT_command.tableColumnData.get(col.field);
        if (!vv) {
          vv = null;
          if (
            this.GT_command.oldMainRec &&
            this.GT_command.oldMainRec[fieldName]
          ) {
            vv = this.GT_command.oldMainRec[col.field];
          }
        }
        this.GT_command.tableColumnData.set(col.field, vv);
        tableColumnData[col.field] = vv;
      }
      if (Tsrv.utils.noValue(this.GT_command.tableColumnData.get(fieldName))) {
        this.GT_command.addTableColumnData(fieldName, null);
      }
    });
    this.refAttrMainForm.setColumns(columns);
    this.refAttrMainForm.setFormData(tableColumnData);

    if (this.GT_command.graphEditorState === 'none') {
      this.refAttrMainForm.setModify(false);
    } else {
      this.refAttrMainForm.setModify(true);
    }
  }

  onAttrNodeLabelChange(e?: any) {
    const m = this.currNode.item.getModel();
    m.label = this.nodeAttrData['nodeLabel'];
    this.refFlowchart.GT_editor.G_graph.updateItem(
      this.currNode.item.getID(),
      m
    );

    this.refFlowchart.GT_editor.G_graph.read(
      this.refFlowchart.GT_editor.G_graph.save()
    );
  }

  onCardBoxValChange(v: boolean) {
    this.isShowNodeForm = v;
  }

  onAttrChange(e) {
    const eType: string = e.eventType as string;
    const currFieldName: string = e.data.property;
    const data: any = e.data.data;
    const m = this.currNode.item.getModel();
    const nodeID = this.currNode.item.getID();

    let eField: string = currFieldName;
    const eFs = eField.split('|');
    if (eFs.length === 4 && eFs[0] === 'm2o') {
      eField = eFs[1];
    } else if (eFs.length === 3 && eFs[0] === 'slc') {
      eField = eFs[1];
    }

    this._config.nodeColumns.forEach(col => {
      // 节点字段与节点名关联 在功能配置时指定 赋值节点名
      if (col?.isNodeName && eField === col.field) {
        this.nodeAttrData.nodeLabel = e.data.data[currFieldName] ?? '';
        this.onAttrNodeLabelChange();
      }
    });
    switch (eType) {
      case 'focus':
        break;
      case 'blur':
        break;
      case 'dochange':
        this.GT_command.addNodeColumnData(nodeID, {
          field: currFieldName,
          value: data[currFieldName]
        } as ifs.I_fv);
        if (eField !== currFieldName) {
          this.GT_command.addNodeColumnData(nodeID, {
            field: eField,
            value: data[eField]
          } as ifs.I_fv);
        }
        this.GT_command.addNodeColumnData(nodeID, {
          field: 'node_id',
          value: nodeID
        } as ifs.I_fv);
        m.data = this.GT_command.nodeColumnData.get(nodeID);

        this.refFlowchart.GT_editor.doUpdate(nodeID, m);
        break;
      case 'input':
        this.GT_command.addNodeColumnData(nodeID, {
          field: currFieldName,
          value: data[currFieldName]
        } as ifs.I_fv);
        if (eField !== currFieldName) {
          this.GT_command.addNodeColumnData(nodeID, {
            field: eField,
            value: data[eField]
          } as ifs.I_fv);
        }
        this.GT_command.addNodeColumnData(nodeID, {
          field: 'node_id',
          value: nodeID
        } as ifs.I_fv);
        m.data = this.GT_command.nodeColumnData.get(nodeID);

        this.refFlowchart.GT_editor.doUpdate(nodeID, m);
        break;

      default:
    }
  }

  onAttrMainChange(e) {
    let eField: string = e.data.field;
    const eFs = eField.split('|');
    if (eFs.length === 4 && eFs[0] === 'm2o') {
      eField = eFs[1];
    } else if (eFs.length === 3 && eFs[0] === 'slc') {
      eField = eFs[1];
    }

    this._config.tableColumns.forEach(col => {
      // 表字段与节点名关联 在功能配置时指定 赋值节点名
      if (col?.isNodeName && eField === col.field) {
        this.nodeAttrData.nodeLabel = e.data.data[e.data.field] ?? '';
        this.onAttrNodeLabelChange();
      }
    });
    const eType: string = e.eventType as string;
    const field = e.data.property;

    // const val = { field, value: e.data.data[field] } as ifs.I_fv;
    switch (eType) {
      case 'focus':
        break;
      case 'blur':
        break;
      case 'dochange':
        this.GT_command.addTableColumnData(field, e.data.data[field]);
        if (eField !== field) {
          this.GT_command.addTableColumnData(eField, e.data.data[eField]);
        }
        break;
      case 'input':
        // this.GT_command.tableColumnData.add(val);
        this.GT_command.addTableColumnData(field, e.data.data[field]);
        if (eField !== field) {
          this.GT_command.addTableColumnData(eField, e.data.data[eField]);
        }
        break;

      default:
    }
  }

  onAfterRender(e) {
    const nodes = e.e.getNodes();
    if (Tsrv.utils.noValue(nodes)) {
      return;
    }
    const fNodes = nodes.filter(el => el.getModel().type !== 'gIfNode');
    if (Tsrv.utils.noValue(fNodes)) {
      return;
    }
    const node = fNodes[0];
    const item = node.getModel();
    node.setState('hover', true, item);
    this.searchChildComp(node.getID(), item);

    setTimeout(() => {
      node.setState('hover', false, item);
    }, 500);
  }

  getActionCfg() {
    return this._config.action;
  }
}
</script>
<style lang="scss" scoped>
.edirot {
  height: 100%;
  width: 100%;
  padding: 0;
  position: relative;
}
::v-deep.node-attr {
  position: relative;
  float: right;
  width: 100%;
  height: 100%;
  padding: 2px;
  overflow-y: auto;
  .title {
    margin-bottom: 6px;
  }

  .panel {
    padding: 8px;
    .label {
      display: flex;
      // justify-content: center;
      align-items: center;
      padding: 6px;
      .label-name {
        margin-right: 6px;
      }
      .label-id {
        margin-right: 20px;
      }
      .input {
        flex: 1;
      }
    }
    .wy-grid {
      .vxe-form {
        .vxe-form--wrapper {
          flex-direction: column;
          .vxe-form--item {
            width: 100%;
          }
        }
      }
    }
  }
  .fullscreen {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
  }
}
</style>
